#include<cstdio>
#include<iostream>
#include<string>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<unistd.h>

class UdpSocket{
  private:
    int _sockfd; //贯穿了上下文，每-个操作都涉及到套接字描述符
  public:
    UdpSocket():_sockfd(-1){}
    bool Socket()//创建套接字,其中的地址域类型这些都是固定
    {
      _sockfd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
      if(_sockfd <0)
      {
        perror("socket error");
        return false;
      }
      return true;

    }
    bool Bind(const std::string &ip, int port){ //绑定地址信息
      struct sockaddr_in addr;//定义IPv4地址结构，然后逐个赋值
      addr.sin_family = AF_INET;//地址域类型
      addr.sin_port = htons(port);//端口
      addr.sin_addr.s_addr = inet_addr(ip.c_str());//将一个字符串的ip地址转换为网络字节序的ip地址
      socklen_t len = sizeof(addr);//地址结构的长度
      int ret = bind(_sockfd,(struct sockaddr*)&addr,len);
      if(ret <0)
      {
        perror("bind error");
        return false;
      }
      return true;
    }
    bool Send(const std::string &data, const std::string &ip, int port){
    //客户端实际上是不需要接收服务器地址的，因为它本身就知道
      struct sockaddr_in peeraddr;      //定义IPv4地址结构，然后逐个赋值
      peeraddr.sin_family = AF_INET;//地址域类型
      peeraddr.sin_port = htons(port);//端口
      peeraddr.sin_addr.s_addr = inet_addr(ip.c_str());//将一个字符串的ip地址转换为网络字节序的ip地址
      socklen_t len = sizeof(struct sockaddr_in);//地址结构的长度
      int ret = sendto(_sockfd,&data[0],data.size(), 0,(struct sockaddr*)&peeraddr,len) ;
      if(ret < 0)
      {
        perror("sendto error");
        return false;
      }
      return true;




    }
    bool Recv(std::string *buf, std::string *ip = NULL, int *port = NULL){//接收数据
      struct sockaddr_in peeraddr;      //定义IPv4地址结构，然后逐个赋值
       socklen_t len = sizeof(struct sockaddr_in);//地址结构的长度
       char tmp[4096] = {0};
       int ret = recvfrom(_sockfd, tmp, 4095, 0, (struct sockaddr*)&peeraddr, &len);
       if(ret < 0)
       {
         perror("recv error");
         return false;
       }
       //并没有使用赋值操作，因为赋值是字符串操作，遇到反斜杠0就停止了，但是网络传输，什么数据都有可能，因为需要不管什么数据，只管截取指定长度
       buf->assign(tmp, ret);//从tmp字符串开始截取ret长度的数据到buf中—>给buf申请一个长度为ret的空间。
       if(ip!=NULL) *ip = inet_ntoa(peeraddr.sin_addr);
       if(port != NULL) *port = ntohs(peeraddr.sin_port);
       return true;

    }
    bool Close(){
      if(_sockfd >= 0)
      {
        close(_sockfd);
      }
      return true;
    }
    //
};

